#pragma once

#include "ps/particle_system.h"

#include <vtkGlyph3D.h>
#include <vtkActor.h>
#include <vtkFloatArray.h>
#include <vtkGlyph3DMapper.h>
#include <vtkNamedColors.h>
#include <vtkPointSource.h>
#include <vtkPolyDataMapper.h>
#include <vtkProperty.h>
#include <vtkSphereSource.h>
#include <vtkSmartPointer.h>
#include <vtkPointData.h>

#include <cstdlib>
#include <ctime>


// static vtkSmartPointer<vtkActorCollection> particles(std::vector<PS::ptype>& ps)
// {
//     const auto N = ps.size();
//     auto rst = vtkSmartPointer<vtkActorCollection>::New();

//     for(size_t i = 0; i < N; ++i)
//     {
//         // Create a sphere source (template sphere)
//         auto sphereSource = vtkSmartPointer<vtkSphereSource>::New();
//         sphereSource->SetCenter(ps[i].position()[0], ps[i].position()[1], 0.0);
//         sphereSource->SetRadius(ps[i].radius());
//         sphereSource->SetThetaResolution(64);
//         sphereSource->SetPhiResolution(64);

//         auto mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
//         mapper->SetInputConnection(sphereSource->GetOutputPort());

//         auto actor = vtkSmartPointer<vtkActor>::New();
//         actor->SetMapper(mapper);

//         rst->AddItem(actor);
//     }

//     return rst;
// }

static vtkSmartPointer<vtkActor> particles(std::vector<PS::ptype>& ps)
{
    const auto N = ps.size();

    // Create a sphere source (template sphere)
    vtkSmartPointer<vtkSphereSource> sphereSource = vtkSmartPointer<vtkSphereSource>::New();
    sphereSource->SetThetaResolution(64);
    sphereSource->SetPhiResolution(64);

    // Create a point source to generate the positions of the spheres
    vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New();
    for (vtkIdType i = 0; i < N; ++i)
    {
        const auto pos = ps[i].position();
        points->InsertNextPoint(pos[0], pos[1], 0.0);
    }

    vtkSmartPointer<vtkPolyData> polyData = vtkSmartPointer<vtkPolyData>::New();
    polyData->SetPoints(points);

    // Create a scalar array for radii
    vtkSmartPointer<vtkFloatArray> radii = vtkSmartPointer<vtkFloatArray>::New();
    radii->SetName("Radii");
    radii->SetNumberOfComponents(1);
    radii->SetNumberOfTuples(N);

    // Set random radii for the spheres (or set your specific radii)
    for (vtkIdType i = 0; i < N; ++i)
    {
        radii->SetValue(i, ps[i].radius());
    }

    // Add the scalar array to the polyData
    polyData->GetPointData()->SetScalars(radii);

    // Create a glyph3D mapper
    vtkSmartPointer<vtkGlyph3DMapper> glyphMapper = vtkSmartPointer<vtkGlyph3DMapper>::New();
    glyphMapper->SetSourceConnection(sphereSource->GetOutputPort());
    glyphMapper->SetInputData(polyData);
    glyphMapper->SetScalarModeToUsePointFieldData();
    glyphMapper->SetScaleArray("Radii");
    glyphMapper->SetScaling(true);

    // Create an actor
    vtkSmartPointer<vtkActor> glyphActor = vtkSmartPointer<vtkActor>::New();
    glyphActor->SetMapper(glyphMapper);

    return glyphActor;
}